import { getRun } from "@autoscholar/core"; import { publicationDecisions, qualityGateResults, reviewFindings } from "@autoscholar/db"; import { asc, desc, eq } from "drizzle-orm"; import Link from "next/link"; import { notFound } from "next/navigation"; import { StatusBadge } from "@/components/StatusBadge"; import { fmtDateTime } from "@/lib/format"; import { db } from "@/lib/server/db"; import { OverrideForm } from "./OverrideForm"; export const dynamic = "force-dynamic"; const NON_OVERRIDABLE = [ "worker.real", "references.verified", "pdf.valid", "secrets.none", "attempt.final", "checksums.valid", "results.consistency", "data.provenance", "claims.traced", "contract.artifacts", "disclosure.present", ]; export default async function QualityDetail({ params }: { params: Promise<{ runId: string }> }) { const { runId } = await params; const d = db(); let data: Awaited>; try { data = await getRun(d, runId); } catch { notFound(); } const gates = await d .select() .from(qualityGateResults) .where(eq(qualityGateResults.runId, runId)) .orderBy(desc(qualityGateResults.createdAt), asc(qualityGateResults.gate)); const evalIds = [...new Set(gates.map((g) => g.evaluationId))]; const findings = await d .select() .from(reviewFindings) .where(eq(reviewFindings.runId, runId)) .orderBy(asc(reviewFindings.round)); const decisions = await d .select() .from(publicationDecisions) .where(eq(publicationDecisions.runId, runId)) .orderBy(desc(publicationDecisions.createdAt)); const latest = gates.filter((g) => g.evaluationId === evalIds[0]); const failedHard = latest.filter((g) => g.severity === "hard" && g.status === "fail"); const blocked = failedHard.filter((g) => NON_OVERRIDABLE.includes(g.gate)); return (

Quality

{data.run.title}

policy {data.run.qualityPolicyVersion} ·{" "} run ·{" "} qa-report.json

{gates.length === 0 && (
No evaluation yet. The scheduler evaluates runs in quality_check.
)} {evalIds.map((id, i) => { const g = gates.filter((x) => x.evaluationId === id); return (

Evaluation {i === 0 ? "(latest)" : ""}{" "} {id.slice(0, 8)} · {fmtDateTime(g[0]?.createdAt)}

{g.filter((x) => x.status === "pass").length} pass ·{" "} {g.filter((x) => x.status === "fail").length} fail ·{" "} {g.filter((x) => x.status === "warn").length} warn ·{" "} {g.filter((x) => x.status === "skip").length} skip

{g.map((x) => ( ))}
Gate Severity Status Message Evidence
{x.gate} {NON_OVERRIDABLE.includes(x.gate) && ( non-overridable )} {x.severity} {x.message} {Object.keys(x.evidence).length ? (
show
                            {JSON.stringify(x.evidence, null, 1)}
                          
) : ( "—" )}
); })} {findings.length > 0 && (

Reviewer findings

    {findings.map((f) => (
  • {f.title}{" "} round {f.round} · {f.category} · {f.resolution}

    {f.detail}

    {f.proposedTest &&

    Proposed test: {f.proposedTest}

    }
  • ))}
)}

Publication decisions

{decisions.length === 0 ? (

None.

) : (
    {decisions.map((x) => (
  • {" "} {x.decision} by {x.decidedBy} ·{" "} {fmtDateTime(x.createdAt)} {x.override && override}

    {x.rationale}

  • ))}
)}
{data.run.status === "quality_failed" && (

Authorized override

{blocked.length > 0 ? (

Cannot override: scientific blockers failed ({blocked.map((b) => b.gate).join(", ")}). Fix the research and retry the run instead.

) : ( x.gate)} /> )}
)}
); }